home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / ui / screen-ui.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  51KB  |  1,935 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4. */
  5.  
  6. /* This is a simple screen user interface for making WAIS queries
  7.  * It is the strange offspring of waisq and curses..
  8.  *
  9.  * Revision 1.2 initial version by jcurran@nnsc.nsf.net 
  10.  *   (dedicated to Suzi, Alex, et. al.)          
  11.  *
  12.  * Revision 1.5 changes 12/91 by datta@cs.uwp.edu
  13.  *
  14.  *   added page up/down 'J/K'
  15.  *   screen state now returns to normal after piping commands
  16.  *   added mail 'm' option 
  17.  *   fixed number entry on source selection to allow for up to MAXINT sources
  18.  *   there is now a pause after viewing a document so if the pager is 'more'
  19.  *         the user will not miss the last screen.
  20.  *
  21.  * Revision 1.6 changes 01/92 by jcurran@nnsc.nsf.net
  22.  *
  23.  *   fixed common_wais_dir on help message
  24.  *   change default common dir to /usr/lib/wais-sources
  25.  *   fix formatting for >99 sources
  26.  *   add ^v aliases for page down, <esc>v for page up
  27.  *   add "/" (find) to find source
  28.  *   add "/" (find) to find result
  29.  *   simplify <return> processing for users
  30.  *   changed the view source information to pipe through $PAGER or 'more'
  31.  *         to allow the use of source descriptions larger than 1 screen.
  32.  *         (done by datta@cs.uwp.edu)
  33.  * 
  34.  * Revision 1.7 changes 01/92 by jcurran@nnsc.nsf.net
  35.  *
  36.  *   fixed miscellaneous selection bugs
  37.  *   added option processing and option screen
  38.  *
  39.  *
  40.  * Notes:
  41.  *   If there are ever more than 999 sources screen display will need
  42.  *       changes.
  43.  *
  44.  *   The use of mvprintw() is dangerous unless there is window bounds
  45.  *       checking. The curses with ULTRIX 4.2, BSD 4.3 and BSD 4.3 reno
  46.  *       have unpredictable results when the window size is exceeded.
  47.  *       Keep this in mind for further enhancements.
  48.  *
  49.  *   The ULTRIX curses.h may be missing some entries and may require
  50.  *       updating. If so, add a DEFINE ULTRIX when you compile
  51.  *
  52.  */
  53.  
  54. #include <curses.h>
  55. #include <signal.h>
  56. #include <setjmp.h>
  57. #include <ctype.h>
  58. #include <ui.h>
  59. #include <sockets.h>
  60. #include <sys/types.h>
  61. #include <netinet/in.h>
  62.  
  63. #if (defined(ULTRIX) || defined(ultrix))
  64. /*
  65.  * ULTRIX 4.2 curses.h is missing these entries
  66.  */
  67. #define    erasechar()    (_tty.sg_erase)
  68. #define    killchar()    (_tty.sg_kill)
  69. #endif /* def ULTRIX */
  70.  
  71. #define STRINGSIZE    256
  72.  
  73. #include "wais.h"
  74. #define MAIN
  75. #include "globals.h"
  76.  
  77. #define    WAIS_SERVICE    "z39_50"
  78.  
  79. #define WAISSCREEN_NAME     "SWAIS"
  80. #define WAISSCREEN_VERSION  "$Revision: 1.10 $"
  81. #define WAISSCREEN_AUTHOR   "John Curran (jcurran@nnsc.nsf.net)"
  82.  
  83. #ifndef COMMON_SOURCE_DIR
  84. #define COMMON_SOURCE_DIR "/usr/lib/wais-sources"
  85. #endif
  86.  
  87. /* SWAIS PROGRAM STATES - each decade shares common screen (0-9, 10-19, etc) */
  88. #define    UNKNOWN            0
  89. #define    GETSOURCES    10
  90. #define    GETKEYWORDS    11
  91. #define    MAKEQUERY    12
  92. #define    SHOWRESULTS    20
  93. #define    GETOPTIONS    30
  94. #define    LEAVEPROGRAM    90
  95.  
  96. typedef int programstate;
  97.  
  98. /* SWAIS OPTION TYPES */
  99. #define    OPTION_BOOLEAN    0
  100. #define OPTION_INTEGER    1
  101. #define    OPTION_STRING    2
  102.  
  103. typedef struct option {
  104.   char name[STRINGSIZE];
  105.   char desc[STRINGSIZE];
  106.   int  type;
  107.   void (* update)();
  108.   union {
  109.     int*  intptr;
  110.     char* charptr;
  111.   } var;
  112. } _Option, *Option;
  113.  
  114. /* options */
  115. #define MAXOPTIONS 6
  116. int  option_widetitles=FALSE;
  117. int  option_sortsources=TRUE;
  118. #if 0
  119. int  option_pagerpause=TRUE;
  120. #else
  121. int  option_pagerpause=FALSE;
  122. #endif
  123.  
  124. _Option options[MAXOPTIONS+1];
  125.             
  126. char* log_file_name = NULL;
  127. FILE* logfile = NULL;
  128. programstate state;
  129. programstate new_state;
  130. jmp_buf main_env;
  131. char keywords[STRINGSIZE];
  132. SList Selected_Sources;
  133. char command[STRINGSIZE];
  134. char *sdir, *cdir;
  135.  
  136. #define MAXSELECTIONS 500
  137. #define NOSELECTION -999999
  138. char select_line[MAXSELECTIONS][STRINGSIZE];
  139. int  selection; /* 1 to max_selection */
  140. int  max_selection; /* limit on selection */
  141. int  current_page; /* 0 to needed pages; preset to -1 to force refresh */
  142. int  page_length; /* number of selections per page */
  143.  
  144. /* routine specific selection number */
  145. int source_selection=1;
  146. int result_selection=1;
  147. int option_selection=1;
  148.  
  149. extern unsigned int sleep _AP((unsigned int seconds));
  150.  
  151. void SortSources()
  152. {
  153.   Boolean Changed = TRUE;
  154.   Source s;
  155.   SList sl;
  156.  
  157.   while(Changed) {
  158.     Changed = FALSE;
  159.     for(sl = Sources; sl->nextSource != NULL; sl = sl->nextSource) {
  160.       if(sl->nextSource->thisSource->name == NULL) {
  161.     Changed = TRUE;
  162.     sl->nextSource = sl->nextSource->nextSource;
  163.       }
  164.       else
  165.     if(0 < strcasecmp(sl->thisSource->name, sl->nextSource->thisSource->name)) {
  166.       Changed = TRUE;
  167.       s = sl->thisSource;
  168.       sl->thisSource = sl->nextSource->thisSource;
  169.       sl->nextSource->thisSource = s;
  170.     }
  171.     }
  172.   }
  173. }
  174.  
  175. void screenend() {
  176.     signal(SIGINT,SIG_IGN);
  177.     clear();
  178.     refresh();
  179.     endwin();
  180.     echo();
  181. }
  182.  
  183. void startover() {
  184.         longjmp(main_env,1);
  185. }
  186.  
  187. void screenstart() {
  188.     static int init;
  189.     if (!init) {
  190.       initscr();
  191.       init=1;
  192.     } else {
  193. /*    wrefresh(); Maybye they meant refresh... yeah, thats it...
  194.             andyj */
  195.     refresh();
  196.     }
  197.       cbreak();
  198.       noecho();
  199.       leaveok(stdscr,FALSE);
  200.       signal(SIGINT,startover);
  201. }
  202.  
  203. void
  204. display_context(context)
  205. char    *context;
  206. {
  207.   mvprintw(LINES-3,0,context);
  208.   clrtoeol();
  209.   refresh();
  210. }
  211.  
  212. void
  213. display_prompt(prompt)
  214. char    *prompt;
  215. {
  216.   mvprintw(LINES-1,0,prompt);
  217.   clrtoeol();
  218.   refresh();
  219. }
  220.  
  221. void
  222. display_highlighted(str)
  223. char    *str;
  224. {
  225.   standout(); 
  226.   mvprintw(LINES-1,0,str);
  227.   standend();
  228.   printw(" ");
  229.   clrtoeol();
  230.   refresh();
  231. }
  232.  
  233. void
  234. PrintStatus(str)
  235. char *str;
  236. {
  237.    if (stdscr!=NULL) {
  238.      display_highlighted(str);
  239.      sleep(2);
  240.    }
  241.    else
  242.      fprintf(stderr,"%s\n",str);
  243. }
  244.  
  245. char *
  246. firstphrase(str)
  247. char *str;
  248. {
  249.   char *res;
  250.   int  n;
  251.  
  252.   res = str;
  253.   if ((n=strcspn(str," "))!=0)
  254.     if ((n>4) && (str[n-4]=='.')) {
  255.  
  256.     n = n - 4;
  257.     res = s_malloc(n+1);
  258.     strncpy(res,str,n);
  259.   }
  260.   return res;
  261. }
  262.  
  263. void
  264. format_option(str,opt)
  265. char *str;
  266. Option opt;
  267. {
  268.   switch (opt->type) {  
  269.     case OPTION_STRING: sprintf(str,"%s",  (opt->var.charptr) );
  270.              break;
  271.     case OPTION_INTEGER: sprintf(str,"%d", * (opt->var.intptr) );
  272.              break;
  273.     case OPTION_BOOLEAN: if (* (opt->var.intptr) == TRUE)
  274.                 sprintf(str,"on");
  275.               else
  276.                 sprintf(str,"off");
  277.              break;
  278.   }
  279. }
  280.  
  281. jmp_buf local_env;
  282.  
  283. char fpath[STRINGSIZE];
  284. void
  285. start_use(fd)
  286. FILE **fd;
  287. {
  288.   *fd = fopen(fpath,"w+");
  289. }
  290. void
  291. end_use(fd)
  292. FILE **fd;
  293. {
  294.   fclose(*fd);
  295. }
  296.  
  297. void
  298. null()
  299. {
  300. }
  301.  
  302. void
  303. Refresh_sources()
  304. {
  305.     FreeSources(Sources);
  306.     Sources = NULL;
  307.     ReadSourceDirectory(sdir,TRUE);
  308.     ReadSourceDirectory(cdir,TRUE);
  309.     if (NumSources == 0) {
  310.       PrintStatus("Error: Unable to find any WAIS information sources.");
  311.       exit(-1);
  312.     }
  313.     if (option_sortsources==TRUE) SortSources();
  314. }
  315.  
  316. void
  317. UseWaisDocument(q, doc)
  318. Question q;
  319. DocumentID doc;
  320. {
  321.   char message[STRINGSIZE];
  322.  
  323.   if (strcmp(doc->doc->type, "WSRC")) {
  324.     fprintf(stderr, "%s", "%s is not a WAIS source.  You can only USE WAIS sources.",
  325.           firstphrase(trim_junk(doc->doc->headline)));
  326.     /* PrintStatus("%s is not a WAIS source.  You can only USE WAIS sources.",
  327.         firstphrase(trim_junk(doc->doc->headline))); */
  328.   }
  329.   else {
  330.     sprintf(message,"Retrieving: %s\n", firstphrase(trim_junk(doc->doc->headline)));
  331.     PrintStatus(message);
  332.  
  333.     sprintf(fpath,"%s%s.src", sdir, firstphrase(trim_junk(doc->doc->headline)));
  334.     RetrieveWaisDocument(start_use, end_use, q, doc);
  335.  
  336.     sprintf(message,"Adding Source: %s\n", firstphrase(trim_junk(doc->doc->headline)));
  337.     PrintStatus(message);
  338.     Refresh_sources();
  339.   }
  340.  
  341.  
  342. jmp_buf local_env;
  343.  
  344. void screen_catchpipe(sig, code, scp, addr)
  345.           int sig, code;
  346.           struct sigcontext *scp;
  347.           char *addr;
  348. {
  349.    longjmp(local_env,1);
  350. }
  351.  
  352. char pipe_cmd[STRINGSIZE];
  353.  
  354. void
  355. start_pipe(pipefd)
  356. FILE **pipefd;
  357. {
  358.   screenend();
  359.   *pipefd = popen(pipe_cmd,"w");
  360. }
  361. void
  362. end_pipe(pipefd)
  363. FILE **pipefd;
  364. {
  365.   pclose(*pipefd);
  366. }
  367.  
  368. void
  369. PipeWaisDocument(q, doc, cmd)
  370. Question q;
  371. DocumentID doc;
  372. char *cmd;
  373. {
  374.   char message[STRINGSIZE];
  375.  
  376.  sprintf(message,"Retrieving: %s\n",firstphrase(trim_junk(doc->doc->headline)));
  377.  PrintStatus(message);
  378.  
  379.   strcpy(pipe_cmd,cmd);
  380.   signal(SIGPIPE,screen_catchpipe);
  381.   if (setjmp(local_env)==0) RetrieveWaisDocument(start_pipe,end_pipe,q,doc); 
  382.   signal(SIGPIPE,SIG_DFL);
  383. }
  384.  
  385. void
  386. FreeSourceList(sources)
  387. SourceList sources;
  388. {
  389.  SourceList s, n;
  390.  
  391.  for (s = sources; s != NULL; s = n) {
  392.    if (s->thisSource != NULL) {
  393.       if (s->thisSource->filename != NULL)
  394.     s_free(s->thisSource->filename);
  395.       s_free(s->thisSource);
  396.    }
  397.  
  398.    n = s->nextSource;
  399.    s_free(s);
  400.  }
  401. }
  402.  
  403. void AddQuestionSource(question, sourcename)
  404. Question question;
  405. char *sourcename;
  406. {
  407.   SourceList tmp;
  408.   SourceList s;
  409.   SourceID sid;
  410.  
  411.   sid = (SourceID)s_malloc(sizeof(_SourceID));
  412.   sid->filename = s_strdup(sourcename);
  413.   s = (SourceList)s_malloc(sizeof(_SourceList));
  414.   s->thisSource = sid;
  415.   s->nextSource = NULL;
  416.   tmp = question->Sources;
  417.   question->Sources = s;
  418.   if (tmp != NULL) 
  419.      s->nextSource = tmp;
  420. }
  421.  
  422. void
  423. usage(name)
  424. char *name;
  425. {
  426.     fprintf(stderr,"Usage: %s\n",name);
  427.     fprintf(stderr,"  [-s sourcname]          select sourcename for search\n");
  428.     fprintf(stderr,"  [-S sourcedir]          defaults to ~/wais-sources\n");
  429.     fprintf(stderr,"  [-C common_sourcedir]   defaults to %s\n",COMMON_SOURCE_DIR);
  430.     fprintf(stderr,"  [-h]                  this help message\n");
  431.     fprintf(stderr,"  [keywords]\n");
  432. }
  433.  
  434.  
  435. SourceID FindQuestionSource(sourcelist, sourcename) 
  436. SourceList sourcelist;
  437. char  *sourcename;
  438. {
  439.    SourceList tmpsource;
  440.    for(tmpsource = sourcelist; tmpsource != NULL; 
  441.                                tmpsource = tmpsource->nextSource) {
  442.     if (tmpsource->thisSource != NULL)
  443.        if (!strcmp(sourcename, tmpsource->thisSource->filename)) 
  444.      return(tmpsource->thisSource);
  445.    }
  446.    return(NULL);
  447. }
  448.  
  449. Source FindSource(sourcelist, sourcename) 
  450. SList sourcelist;
  451. char  *sourcename;
  452. {
  453.    SList tmpsource;
  454.    for(tmpsource = sourcelist; tmpsource != NULL; 
  455.                                tmpsource = tmpsource->nextSource) {
  456.     if (tmpsource->thisSource != NULL)
  457.        if (!strcmp(sourcename, tmpsource->thisSource->name)) 
  458.      return(tmpsource->thisSource);
  459.    }
  460.    return(NULL);
  461. }
  462.  
  463. void
  464. DumpSources(sourcelist)
  465. SList sourcelist;
  466. {
  467.    SList tmpsource;
  468.   
  469.    if (sourcelist == NULL) {
  470.       printf("Sourcelist NULL");
  471.       return;
  472.    }
  473.  
  474.    printf(" Dump of Sourcelist \n");
  475.    for(tmpsource = sourcelist; tmpsource != NULL; tmpsource = tmpsource->nextSource) {
  476.       if (tmpsource->thisSource == NULL) 
  477.          printf("    thisSource NULL\n");
  478.       else
  479.          printf("    thisSource = %s\n",tmpsource->thisSource->name);
  480.       if (tmpsource->nextSource == NULL) 
  481.          printf("    nextSource NULL\n");
  482.       else
  483.          printf("    following nextSource ->\n");
  484.     }
  485. }
  486.  
  487.  
  488. SList
  489. AddSource(sourcelist,currentsource)
  490. SList sourcelist;
  491. Source currentsource;
  492. {
  493.    Source s;
  494.    SList tmpsource;
  495.    SList last;
  496.   
  497.    if (sourcelist == NULL)
  498.      sourcelist = makeSList(NULL,NULL);
  499.  
  500.    last=sourcelist;
  501.  
  502.    for(tmpsource = sourcelist; tmpsource != NULL; 
  503.        last = tmpsource, tmpsource = tmpsource->nextSource) 
  504.          if (tmpsource->thisSource != NULL)
  505.         if (!strcmp(currentsource->name, tmpsource->thisSource->name)) 
  506.           return(sourcelist);
  507.  
  508.    s = (Source) s_malloc(sizeof(_Source));
  509.    s->initp = currentsource->initp;
  510.    s->name  = s_strdup(currentsource->name);
  511.    s->directory  = s_strdup(currentsource->directory);
  512.      
  513.    if (last->thisSource == NULL) 
  514.      last->thisSource = s;
  515.    else
  516.      last->nextSource = makeSList(s, NULL); 
  517.    return(sourcelist);
  518. }
  519.  
  520. SList
  521. DeleteSource(sourcelist,currentsource)
  522. SList sourcelist;
  523. Source currentsource;
  524. {
  525.    SList s;
  526.    SList tmpsource;
  527.    SList last;
  528.   
  529.    if (sourcelist == NULL)
  530.      return(NULL);
  531.  
  532.    last=sourcelist;
  533.  
  534.    for(tmpsource = sourcelist; tmpsource != NULL; 
  535.        last = tmpsource, tmpsource = tmpsource->nextSource) 
  536.          if (tmpsource->thisSource != NULL)
  537.         if (!strcmp(currentsource->name, tmpsource->thisSource->name)) {
  538.            if(tmpsource->thisSource->name != NULL)
  539.          s_free (tmpsource->thisSource->name);
  540.            if(tmpsource->thisSource->directory != NULL)
  541.          s_free (tmpsource->thisSource->directory);
  542.            if(tmpsource->thisSource->maintainer != NULL)
  543.          s_free (tmpsource->thisSource->maintainer);
  544.                
  545.                /* save next link ptr, discard current link */
  546.                s = tmpsource->nextSource; 
  547.                s_free (tmpsource);
  548.  
  549.                /* return next as start if start destroyed */
  550.                if (last==sourcelist)
  551.                  return(s);
  552.           
  553.                /* Splice next into position, return start ptr */
  554.                last->nextSource = s;
  555.                break;
  556.             }
  557.    return(sourcelist);
  558. }
  559.  
  560. char *
  561. fixdirname(dir)
  562. char *dir;
  563. {
  564.   char *res;
  565.  
  566.   if(dir[strlen(dir)-1] == '/') res = dir;
  567.   else {
  568.     res = s_malloc(strlen(dir)+2);
  569.     sprintf(res,"%s/", dir);
  570.   }
  571.   return res;
  572. }
  573.  
  574. int
  575. selection_page(sel)
  576. int sel;
  577. {
  578.   return(((sel-1) / page_length));
  579. }
  580.  
  581. int
  582. selection_line(sel)
  583. int sel;
  584. {
  585.   return(((sel-1) % page_length)+2);
  586. }
  587.   
  588. selection_display(new_sel)
  589. int new_sel;
  590. {
  591.   int new_page;
  592.   int new_selection;
  593.   int sel_offset;
  594.   int k;
  595.  
  596.   standend();
  597.   mvprintw(selection_line(selection),0,"%s",select_line[selection]);
  598.   
  599.   if (new_sel==NOSELECTION) 
  600.     new_selection = selection;
  601.   else
  602.     new_selection = new_sel;
  603.  
  604.   if (new_selection < 1)
  605.       new_selection = max_selection;
  606.   if (new_selection > max_selection) 
  607.       new_selection = 1;
  608.  
  609.   new_page = selection_page(new_selection);
  610.   if (current_page!=new_page) {
  611.     sel_offset = new_page * page_length;
  612.     for (k = 1; k <= page_length; k++) 
  613.       if ((sel_offset+k)<=max_selection)
  614.     mvprintw(1+k,0,"%s",select_line[sel_offset+k]);
  615.       else
  616.     mvprintw(1+k,0,"\n");
  617.   }
  618.  
  619.   if (new_sel!=NOSELECTION) {
  620.      standout();
  621.      mvprintw(selection_line(new_selection),0,"%s",select_line[new_selection]);
  622.      standend();
  623.   }
  624.   move(selection_line(new_selection),0);
  625.   current_page = new_page;
  626.   selection = new_selection;
  627.   refresh();
  628. }
  629.  
  630. void
  631. title_display(title,status,status_count)
  632. char *title;
  633. char *status;
  634. int  status_count;
  635. {
  636.   mvprintw(0,0,WAISSCREEN_NAME);
  637.   standout();
  638.   mvprintw(0,COLS/2-(strlen(title)/2),"%s", title);
  639.   standend();
  640.   mvprintw(0,COLS-(strlen(status)+4),"%s %2ld", status, status_count);
  641. }
  642.  
  643. void
  644. show_source_entry_help()
  645. {
  646.   int j=2;
  647.  
  648.   clear();
  649.   title_display("Source Selection Help","Page:",1);
  650.   mvprintw(j++,0,"%s\t%s","j, down arrow, ^N","Move Down one source");
  651.   mvprintw(j++,0,"%s\t%s","k, up arrow, ^P  ","Move Up one source");
  652.   mvprintw(j++,0,"%s\t%s","J, ^V, ^D        ","Move Down one screen");
  653.   mvprintw(j++,0,"%s\t%s","K, <esc> v, ^U   ","Move Up one screen");
  654.   mvprintw(j++,0,"%s\t%s","###              ","Position to source number ##");
  655.   mvprintw(j++,0,"%s\t%s","/sss             ","Search for source sss");
  656.   mvprintw(j++,0,"%s\t%s","<space>, <period>","Select current source");
  657.   mvprintw(j++,0,"%s\t%s","=                ","Deselect all sources");
  658.   mvprintw(j++,0,"%s\t%s","v, <comma>       ","View current source info");
  659.   mvprintw(j++,0,"%s\t%s","<ret>            ","Perform search");
  660.   mvprintw(j++,0,"%s\t%s","s                ","Select new sources (refresh sources list)");
  661.   mvprintw(j++,0,"%s\t%s","w                ","Select new keywords");
  662.   mvprintw(j++,0,"%s\t%s","X, -             ","Remove current source permanently");
  663.   mvprintw(j++,0,"%s\t%s","o                ","Set and show swais options");
  664.   mvprintw(j++,0,"%s\t%s","h, ?             ","Show this help display");
  665.   mvprintw(j++,0,"%s\t%s","H                ","Display program history");
  666.   mvprintw(j++,0,"%s\t%s","q                ","Leave this program");
  667.   PrintStatus("Press any key to continue"); 
  668.   getch();
  669. }
  670.  
  671. void
  672. view_source_info(sourcelist,current_s)
  673. SList sourcelist;
  674. Source    current_s;
  675. {
  676.   FILE *fp;
  677.   int j=2;
  678.   char tmp_str[STRINGSIZE];
  679.   sprintf(pipe_cmd,"${PAGER-more}");
  680.   start_pipe(&fp);
  681.   if (NULL != current_s->name) 
  682.     fprintf(fp,"\n%s\t%s\n","Name:       ",current_s->name);
  683.   if (NULL != current_s->directory) 
  684.     fprintf(fp,"%s\t%s\n","Directory:  ",current_s->directory);
  685.   if (NULL != current_s->maintainer) 
  686.     fprintf(fp,"%s\t%s\n","Maintainer: ",current_s->maintainer);
  687.   if (NULL != FindSource(sourcelist,current_s->name)) 
  688.     sprintf(tmp_str,"Yes");
  689.   else
  690.     sprintf(tmp_str,"No");
  691.     fprintf(fp,"%s\t%s\n","Selected:   ",tmp_str);
  692.   format_source_cost(tmp_str,current_s);
  693.     fprintf(fp,"%s\t%s\n","Cost:       ",tmp_str);
  694.   if (current_s->initp) 
  695.     sprintf(tmp_str,"(Accessed)");
  696.   else
  697.     tmp_str[0]='\0';
  698.   if (NULL != current_s->server) 
  699.     fprintf(fp,"%s\t%s %s\n","Server:     ",current_s->server,tmp_str);
  700.   if (NULL != current_s->service)  
  701.     fprintf(fp,"%s\t%s\n","Service:    ",current_s->service);
  702.   if (NULL != current_s->database) 
  703.     fprintf(fp,"%s\t%s\n","Database:   ",current_s->database);
  704.   if (NULL != current_s->description) {
  705.     fprintf(fp,"%s\n","Description:");
  706.     fprintf(fp,"%s\n",current_s->description);
  707.   }
  708.   end_pipe(&fp);
  709.   cbreak();
  710.   noecho();
  711.   PrintStatus("Press any key to continue.");
  712.   getch();
  713. }
  714.  
  715. void
  716. view_result_info(current_doc)
  717. DocumentID current_doc;
  718. {
  719.   int j=2;
  720.   char tmp_str[STRINGSIZE];
  721.  
  722.   clear();
  723.   title_display("Result Information","Page:",1);
  724.  
  725. /*  sure.. someday these might have data. jtc
  726.     GetServer(current_doc->doc->id,tmp_str);
  727.     mvprintw(j++,0,"%s\t%s","Server:     ",tmp_str);
  728.     GetDatabase(current_doc->doc->id,tmp_str);
  729.     mvprintw(j++,0,"%s\t%s","Database:   ",tmp_str);
  730.     GetLocalID(current_doc->doc->id,tmp_str);
  731.     mvprintw(j++,0,"%s\t%s","Local ID:   ",tmp_str);
  732. */
  733.   if (NULL != current_doc->doc->date) 
  734.     mvprintw(j++,0,"%s\t%s","Date:       ",current_doc->doc->date);
  735.   if (NULL != current_doc->doc->headline) 
  736.     mvprintw(j++,0,"%s\t%s","Source:     ",current_doc->doc->source);
  737.   if (NULL != current_doc->doc->headline) 
  738.     mvprintw(j++,0,"%s\t%s","Headline:   ",current_doc->doc->headline);
  739.   if (NULL != current_doc->doc->city) 
  740.     mvprintw(j++,0,"%s\t%s","City:       ",current_doc->doc->city);
  741.   if (NULL != current_doc->doc->stock) 
  742.     mvprintw(j++,0,"%s\t%s","Stock:      ",current_doc->doc->stock);
  743.   if (NULL != current_doc->doc->company) 
  744.     mvprintw(j++,0,"%s\t%s","Company:    ",current_doc->doc->company);
  745.   if (NULL != current_doc->doc->industry) 
  746.     mvprintw(j++,0,"%s\t%s","Industry:   ",current_doc->doc->industry);
  747.   if (NULL != current_doc->doc->type) 
  748.     mvprintw(j++,0,"%s\t%s","Type:       ",current_doc->doc->type);
  749.     mvprintw(j++,0,"%s\t%d","Score       ",current_doc->rawScore);
  750.  
  751.     mvprintw(j++,0,"%s\t%ld","# of Lines: ",current_doc->doc->numLines);
  752.     mvprintw(j++,0,"%s\t%ld","# of Chars: ",current_doc->doc->numChars);
  753.  
  754.   if (NULL != current_doc->doc->sourceID->filename) 
  755.      mvprintw(j++,0,"%s\t%s","SourceID:   ",current_doc->doc->sourceID->filename);
  756.   switch (GetCopyrightDisposition(current_doc->doc->id)) {
  757.   
  758.      case (COPY_WITHOUT_RESTRICTION) : sprintf(tmp_str,"Copy Without Restriction");
  759.                                        break;
  760.      case (ALL_RIGHTS_RESERVED) : sprintf(tmp_str,"All Rights Reserved");
  761.                                        break;
  762.      case (DISTRIBUTION_RESTRICTIONS_APPLY) : sprintf(tmp_str,"Distribution Restrictions Apply");
  763.                                        break;
  764.      default : sprintf(tmp_str,"Unknown");
  765.                                        break;
  766.   }
  767.      mvprintw(j++,0,"%s\t%s","Disposition: ",tmp_str);
  768.  
  769.   PrintStatus("Press any key to continue"); 
  770.   getch();
  771. }
  772.  
  773. void
  774. show_swais_history()
  775. {
  776.   char versiononly[STRINGSIZE];
  777.   int j=2;
  778.  
  779.   clear();
  780.   title_display("SWAIS History","Page:",1);
  781.   mvprintw(j++,0,"%s"," ");
  782.   mvprintw(j++,0,"%s",
  783. "The WAIS (Wide Area Information Service) system is a collection of programs");
  784.   mvprintw(j++,0,"%s",
  785. "which provide for convenient information distribution over wide area networks.");
  786.   mvprintw(j++,0,"%s",
  787. "Tools for both \"publishing\" and accessing information sources are provided.");
  788.   mvprintw(j++,0,"%s",
  789. "The Simple WAIS (SWAIS) interface is an basic access tool designed for those");
  790.   mvprintw(j++,0,"%s",
  791. "focused on data retreival and not computer operation. It provides most of the");
  792.   mvprintw(j++,0,"%s",
  793. "functionality of the more complicated interfaces but features a simple and");
  794.   mvprintw(j++,0,"%s",
  795. "potentially more natural interface.  The functionality supported includes ");
  796.   mvprintw(j++,0,"%s",
  797. "source selection, keyword entry, and automatic document retrieval.");
  798.   mvprintw(j++,0,"%s",
  799. "I hope that this tool may be of use.  Enjoy.");
  800.   mvprintw(j++,0,"%s"," ");
  801.   mvprintw(j++,0,"%s",
  802. "The WAIS system is the result of a joint project between Thinking Machines,");
  803.   mvprintw(j++,0,"%s",
  804. "Apple Computer, and Dow Jones.  For more information on WAIS, send mail to");
  805.   mvprintw(j++,0,"%s",
  806. "\"wais-discussion@think.com\".  The current release of the WAIS software");
  807.   mvprintw(j++,0,"%s",
  808. "is available via anonymous ftp from think.com in subdirectory wais.");
  809.   sscanf(WAISSCREEN_VERSION,"$ %*s %s",versiononly);
  810.   mvprintw(LINES-5,0,"Simple Wais %s [built with %s]", versiononly,VERSION);
  811.   mvprintw(LINES-3,0,"%s", WAISSCREEN_AUTHOR);
  812.  
  813.   PrintStatus("Press any key to continue"); 
  814.   getch();
  815. }
  816.  
  817. void
  818. show_search_results_help()
  819. {
  820.   int j=2;
  821.  
  822.   clear();
  823.   title_display("Search Results Help","Page:",1);
  824.   mvprintw(j++,0,"%s\t\t%s","j, ^N  ","Move Down one item");
  825.   mvprintw(j++,0,"%s\t\t%s","k, ^P  ","Move Up one item");
  826.   mvprintw(j++,0,"%s\t\t%s","J      ","Move Down one screen");
  827.   mvprintw(j++,0,"%s\t\t%s","K      ","Move Up one screen");
  828.   mvprintw(j++,0,"%s\t\t%s","m      ","Mail current item to an address");
  829.   mvprintw(j++,0,"%s\t\t%s","##     ","Position to item number ##");
  830.   mvprintw(j++,0,"%s\t\t%s","/sss   ","Position to item beginning sss");
  831.   mvprintw(j++,0,"%s\t\t%s","<space>","Display current item");
  832.   mvprintw(j++,0,"%s\t\t%s","<return>","Display current item");
  833.   mvprintw(j++,0,"%s\t\t%s","|      ","Pipe current item into a unix command");
  834.   mvprintw(j++,0,"%s\t\t%s","v      ","View current item information");
  835.   mvprintw(j++,0,"%s\t\t%s","s      ","Specify new sources to search");
  836.   mvprintw(j++,0,"%s\t\t%s","u      ","Use it; add it to the list of sources");
  837.   mvprintw(j++,0,"%s\t\t%s","w      ","Make another search with new keywords");
  838.   mvprintw(j++,0,"%s\t\t%s","o      ","Set and show swais options");
  839.   mvprintw(j++,0,"%s\t\t%s","h      ","Show this help display");
  840.   mvprintw(j++,0,"%s\t\t%s","H      ","Display program history");
  841.   mvprintw(j++,0,"%s\t\t%s","q      ","Leave this program");
  842.   PrintStatus("Press any key to continue"); 
  843.   getch();
  844. }
  845.  
  846. int
  847. get_input_string(str)
  848. char str[STRINGSIZE];
  849. {
  850.       int  startcol, startline;
  851.       int  pos;
  852.       char ch;
  853.  
  854.       getyx(stdscr, startline, startcol);
  855.       addstr(str);
  856.       clrtoeol();
  857.       refresh();
  858.  
  859.       pos = strlen(str);
  860.       while(TRUE) {
  861.  
  862.     ch=getch();
  863.         if (ch==killchar()) {
  864.         move(startline, startcol);
  865.         clrtoeol();
  866.         refresh();
  867.         str[0] = 0;
  868.         pos = 0;
  869.         }
  870.         else
  871.            if ((ch==erasechar())||(ch==127)) {
  872.            if (pos>0) {
  873.          str[--pos]='\0';
  874.          mvaddch(startline,startcol+pos,' ');
  875.          move(startline,startcol+pos);
  876.          refresh();
  877.            }
  878.                else {
  879.                  str[0]='\0';
  880.                  break;
  881.                }
  882.        }
  883.            else
  884.           if (ch=='\n')
  885.         break;
  886.               else 
  887.                 if (isprint(ch)){
  888.          str[pos++]=ch;
  889.          str[pos]='\0';
  890.          addch(ch);
  891.          refresh();
  892.               }
  893.  
  894.       }
  895.        
  896.       display_prompt("");
  897.       return(str[0]!='\0');
  898. }
  899.  
  900. void
  901. display_source_selected(sourcelist,currentsource)
  902. SList sourcelist;
  903. Source currentsource;
  904. {
  905.    if (NULL != FindSource(sourcelist,currentsource->name)) {
  906.      mvprintw(selection_line(selection),5,"*");
  907.       }
  908.    else {
  909.       mvprintw(selection_line(selection),5," ");
  910.       }
  911. }
  912.  
  913. void
  914. source_selected(sourcelist,currentsource,sel)
  915. SList sourcelist;
  916. Source currentsource;
  917. {
  918.    if (NULL != FindSource(sourcelist,currentsource->name)) {
  919.          select_line[sel][5] = '*';
  920.       }
  921.    else {
  922.       select_line[sel][5] = ' ';
  923.       }
  924. }
  925.  
  926. programstate
  927. nextstate(question)
  928. Question question;
  929. {
  930.   if ((question->numsources==0) || !(question->modified)) {
  931.      return(GETSOURCES);
  932.   }
  933.     
  934.   return(GETKEYWORDS);
  935. }
  936.  
  937. programstate
  938. makequery_state(question)
  939. Question question;
  940. {
  941.   SList asource;
  942.  
  943.    /* rebuild question source list from Selected_Sources */
  944.    FreeSourceList(question->Sources);
  945.    question->Sources = NULL;
  946.    /* build new question source list */
  947.    for (asource = Selected_Sources; 
  948.      asource != NULL ; asource = asource->nextSource)
  949.        if (asource->thisSource != NULL) 
  950.      AddQuestionSource(question,asource->thisSource->name);
  951.    question->numsources = listlength((List)question->Sources);
  952.  
  953.    question->RelevantDocuments = NULL;
  954.    question->numdocs = listlength((List)question->RelevantDocuments);
  955.    question->ResultDocuments = NULL;
  956.    question->numresdocs = listlength((List)question->ResultDocuments);
  957.  
  958.    SearchWais(question);
  959.    question->modified = FALSE;
  960.  
  961.    if(question->numresdocs > 0) {
  962.      result_selection = 1;
  963.      return(SHOWRESULTS);
  964.    } else 
  965.      return(nextstate(question));
  966. }
  967.  
  968. void
  969. option_screen(question)
  970. Question question;
  971. {
  972.   DocList doclist;
  973.   DocumentID current_doc;
  974.   int k;
  975.   int option_count;
  976.   char fstr[STRINGSIZE];
  977.   char tstr[STRINGSIZE];
  978.   char *sourcename;
  979.  
  980.   option_count = MAXOPTIONS;
  981.  
  982.   title_display("Option Settings","Options:", option_count);
  983.  
  984.   mvprintw(1,2,"#    Option        Value ");
  985.  
  986.   sprintf(fstr,"%%03d:   %%-12.12s  %%-%d.%ds",COLS-22,COLS-22);
  987.  
  988.   for (k=1; k <= option_count; k++) {
  989.      format_option(tstr,options[k]);
  990.      sprintf(select_line[k], fstr, k, options[k].name, tstr);
  991.   }
  992.  
  993.   selection = option_selection;
  994.   current_page = -1;
  995.   max_selection= option_count;
  996.   page_length= MIN(LINES-6, option_count);
  997.   selection_display(NOSELECTION);
  998.  
  999. }
  1000.  
  1001. programstate
  1002. option_state(question)
  1003. Question question;
  1004. {
  1005.  
  1006.   char user_key[STRINGSIZE];
  1007.   char digit_str[STRINGSIZE];
  1008.   int k,miss, option_count;
  1009.  
  1010.   option_count = MAXOPTIONS+1;
  1011.   selection_display(selection);
  1012.   display_context(options[selection].desc);
  1013.   
  1014.   digit_str[0]='\0';
  1015.   while(TRUE) {
  1016.     display_prompt("<space> to change, arrows to move, s for sources, r for results, ? for help");
  1017.     user_key[0]=getch();
  1018.     switch(user_key[0]) {
  1019.     
  1020.     case 'h' : ;
  1021.     case '?' : show_search_results_help();
  1022.       state=UNKNOWN;
  1023.       return(GETOPTIONS);
  1024.          
  1025.       /* forgive me: hardwired arrow keys for vt100 since we're
  1026.      not using SysV curses and bsd curses lacks key support  */
  1027.     case '\033' : user_key[1]=getch();
  1028.       user_key[2]=getch();
  1029.       user_key[3]='\0';
  1030.       if (strcmp(user_key, "\033[A")) {
  1031.     selection_display(selection+1);
  1032.   display_context(options[selection].desc);
  1033.     option_selection = selection;
  1034.     break;
  1035.       }
  1036.       if (strcmp(user_key, "\033[B")) {
  1037.     selection_display(selection-1);
  1038.   display_context(options[selection].desc);
  1039.     option_selection = selection;
  1040.     break;
  1041.       }
  1042.  
  1043.     /* emacs <meta>v page previous */
  1044.     if (user_key[1]=='v') {
  1045.       selection_display(selection-page_length);
  1046.   display_context(options[selection].desc);
  1047.       option_selection = selection;
  1048.       break;
  1049.     }
  1050.         break;
  1051.  
  1052.         case 10   : ;
  1053.         case ' '  : k = selection;
  1054.             switch (options[k].type) {
  1055.             case OPTION_INTEGER : 
  1056.                 digit_str[0]='\0';
  1057.                 mvprintw(LINES-3,0,"New Value: ");
  1058.                 get_input_string(digit_str);
  1059.                 if (atoi(digit_str)!= 0) {
  1060.                   *(options[k].var.intptr) = atoi(digit_str);
  1061.                                   options[k].update();
  1062.                 }
  1063.                 standend();
  1064.                 mvprintw(LINES-3,0," ");
  1065.                 clrtoeol();
  1066.                 break;
  1067.             case OPTION_STRING : 
  1068.                 digit_str[0]='\0';
  1069.                 mvprintw(LINES-3,0,"New Value: ");
  1070.                 if (get_input_string(digit_str)){
  1071.                   strcpy(options[k].var.charptr, digit_str);
  1072.                                   options[k].update();
  1073.                 }
  1074.                 standend();
  1075.                 mvprintw(LINES-3,0," ");
  1076.                 clrtoeol();
  1077.                 break;
  1078.             case OPTION_BOOLEAN : 
  1079.                 if (* (options[k].var.intptr) == TRUE)
  1080.                 *(options[k].var.intptr) = FALSE;
  1081.                 else
  1082.                 *(options[k].var.intptr) = TRUE;
  1083.                                 options[k].update();
  1084.                 break;
  1085.             }
  1086.             state=UNKNOWN;
  1087.             return(GETOPTIONS);
  1088.  
  1089.         case 14   : ;
  1090.         case 'j'  : selection_display(selection+1); 
  1091.   display_context(options[selection].desc);
  1092.               option_selection = selection;
  1093.               break;
  1094.  
  1095.         case 16   : ;
  1096.         case 'k'  : selection_display(selection-1); 
  1097.   display_context(options[selection].desc);
  1098.               option_selection = selection;
  1099.               break;
  1100.  
  1101.         case 'q'  : return(LEAVEPROGRAM);
  1102.         case 's'  : return(GETSOURCES);
  1103.         case 'r'  : if(question->numresdocs > 0) return(SHOWRESULTS);break;
  1104.         case 'w'  : return(GETKEYWORDS);
  1105.                 
  1106.         case 18   : ;
  1107.         case '\f' : wrefresh(curscr);
  1108.                         break;
  1109.  
  1110.             case '/'  : user_key[0] = '\0';
  1111.               mvprintw(LINES-3,0,"Option Name: ");
  1112.               get_input_string(user_key);
  1113.             standend();
  1114.               mvprintw(LINES-3,0," ");
  1115.               clrtoeol();
  1116.             refresh();
  1117.              if (strlen(user_key)) {
  1118.                miss = TRUE;
  1119.                      for (k=1 ; k <= option_count ; k++ ) {
  1120.                     if (!strncasecmp(user_key,options[k].name,
  1121.                 strlen(user_key))) {
  1122.                             selection_display(k);
  1123.                                 option_selection = k;
  1124.                 miss = FALSE;
  1125.                     break;
  1126.                               }
  1127.                     }
  1128.                         if (miss=TRUE) PrintStatus("Unable to find item");
  1129.                         }
  1130.             display_context(options[option_selection].desc);
  1131.                         break;
  1132.  
  1133.      case 4    : ;
  1134.          case 22   : ; /* emacs ctrl-v */
  1135.      case 'J'  : selection_display(selection+page_length);
  1136.   display_context(options[selection].desc);
  1137.                      option_selection = selection;
  1138.              break;
  1139.  
  1140.      case 21   : ;
  1141.          case 'K'  : selection_display(selection-page_length); 
  1142.   display_context(options[selection].desc);
  1143.                      option_selection = selection;
  1144.                      break;
  1145.  
  1146.          default :   if (isdigit(user_key[0])) {
  1147.               digit_str[0] = user_key[0];
  1148.               digit_str[1] = '\0';
  1149.               mvprintw(LINES-3,0,"Item Number: ");
  1150.               get_input_string(digit_str);
  1151.              if (atoi(digit_str)!= 0) {
  1152.                     selection_display(atoi(digit_str));
  1153.                option_selection = selection;
  1154.                 }
  1155.             standend();
  1156.               mvprintw(LINES-3,0," ");
  1157.                         clrtoeol();
  1158.               display_context(options[selection].desc);
  1159.       }
  1160.     }
  1161.   } 
  1162. }
  1163.  
  1164. void
  1165. source_screen(question)
  1166. Question question;
  1167. {
  1168.   int k;
  1169.   int source_count;
  1170.   Source current_s;
  1171.   SList asource;
  1172.   char fstr[STRINGSIZE];
  1173.  
  1174.   source_count = listlength((List)Sources);
  1175.  
  1176.   title_display("Source Selection","Sources:",source_count);
  1177.   mvprintw(1,2,"#            Server                          Source                      Cost");
  1178.  
  1179.   sprintf(fstr,"%%03d:   [%%20.20s]  %%-%d.%ds %%16.16s",COLS-49,COLS-49);
  1180.   k = 1;
  1181.   for (asource = Sources; asource != NULL ; asource = asource->nextSource) {
  1182.  
  1183.      char tmpstr[STRINGSIZE];
  1184.      char cost_str[STRINGSIZE];
  1185.  
  1186.      current_s=asource->thisSource;
  1187.      tmpstr[0]='\0';
  1188.      if (strstr(current_s->name,".src")!=NULL) 
  1189.     strncat(tmpstr, current_s->name, strlen(current_s->name)-4);
  1190.      else
  1191.         strcat(tmpstr, current_s->name);
  1192.      
  1193.      format_source_cost(cost_str,current_s);
  1194.      sprintf(select_line[k], fstr, k, current_s->server, tmpstr, cost_str);
  1195.      source_selected(Selected_Sources,current_s,k);
  1196.      k++;
  1197.   }
  1198.   selection = source_selection;
  1199.   current_page = -1;
  1200.   max_selection=source_count;
  1201.   page_length= MIN(LINES-6, source_count);
  1202.   selection_display(NOSELECTION);
  1203.  
  1204.   mvprintw(LINES-3,0,"Keywords:");
  1205.   mvprintw(LINES-3,10,"%s",question->keywords);
  1206.   refresh();
  1207. }
  1208.  
  1209. programstate
  1210. source_state(question)
  1211. Question question;
  1212. {
  1213.   int miss,k;
  1214.   /* int source_count; */
  1215.   /* Source current_s; */
  1216.   SList asource;
  1217.   char user_key[STRINGSIZE];
  1218.   char digit_str[STRINGSIZE];
  1219.   char message[STRINGSIZE];
  1220.  
  1221.   /* source_count = listlength((List)Sources); */
  1222.   selection_display(selection);
  1223.  
  1224.   digit_str[0]='\0';
  1225.  
  1226.    while(TRUE) {
  1227.  
  1228.      display_prompt("<space> selects, w for keywords, arrows move, <return> searches, q quits, or ?");
  1229.     user_key[0]=getch();
  1230.     switch(user_key[0]) {
  1231.        
  1232.         case 'H' : show_swais_history();
  1233.                        state=UNKNOWN;
  1234.                return(GETSOURCES);
  1235.  
  1236.         case 'h' : ;
  1237.         case '?' : show_source_entry_help();
  1238.                        state=UNKNOWN;
  1239.                return(GETSOURCES);
  1240.         
  1241.         /* forgive me: hardwired arrow keys for vt100 since we're
  1242.            not using SysV curses and bsd curses lacks key support  */
  1243.         case '\033' : user_key[1]=getch();
  1244.               user_key[2]=getch();
  1245.               user_key[3]='\0';
  1246.               if (strcmp(user_key, "\033[A")) {
  1247.                  selection_display(selection+1);
  1248.                              source_selection = selection;
  1249.                              break;
  1250.                           }
  1251.  
  1252.               if (strcmp(user_key, "\033[B")) {
  1253.                  selection_display(selection-1);
  1254.                              source_selection = selection;
  1255.                              break;
  1256.                           }
  1257.  
  1258.               /* emacs <meta>v page previous */
  1259.               if (user_key[1]=='v') {
  1260.                      selection_display(selection-page_length);
  1261.                              source_selection = selection;
  1262.                              break;
  1263.                           }
  1264.  
  1265.                           break;
  1266.  
  1267.         case 'o' : return(GETOPTIONS);
  1268.  
  1269.         case ','  : ;
  1270.         case 'v'  : k = 0;
  1271.             for (asource = Sources; 
  1272.               asource != NULL ; asource = asource->nextSource) {
  1273.               k++;
  1274.               if (k==selection) break;
  1275.             }
  1276.                         view_source_info(Selected_Sources,asource->thisSource); 
  1277.                         state=UNKNOWN;
  1278.                 return(GETSOURCES);
  1279.  
  1280.             case 'X'  : ;
  1281.         case '-'  : k = 0;
  1282.             for (asource = Sources; 
  1283.               asource != NULL ; asource = asource->nextSource) {
  1284.               k++;
  1285.               if (k==selection) break;
  1286.             }
  1287.                         sprintf(fpath,"%s%s.src", sdir, firstphrase(trim_junk(asource->thisSource->name)));
  1288.                         sprintf(message,"Removing Source: %s\n", firstphrase(trim_junk(asource->thisSource->name)));
  1289.             PrintStatus(message);
  1290.  
  1291.                         if (unlink(fpath)==0) {  
  1292.                if (FindSource(Selected_Sources,asource->thisSource->name)) {
  1293.            
  1294.                   Selected_Sources = DeleteSource(Selected_Sources,asource->thisSource);
  1295.                   question->numsources--;
  1296.                   question->modified=TRUE;
  1297.                }
  1298.                FreeSources(Sources);
  1299.                Sources = NULL;
  1300.                ReadSourceDirectory(sdir,TRUE);
  1301.                ReadSourceDirectory(cdir,TRUE);
  1302.                state=UNKNOWN;
  1303.                return(GETSOURCES);
  1304.                        }
  1305.                        PrintStatus("Unable to remove common sources");
  1306.                        break;
  1307.  
  1308.             case '/'  : user_key[0] = '\0';
  1309.               mvprintw(LINES-3,0,"Source Name: ");
  1310.               get_input_string(user_key);
  1311.             standend();
  1312.               mvprintw(LINES-3,0," ");
  1313.               clrtoeol();
  1314.             refresh();
  1315.              if (strlen(user_key)) {
  1316.                k=0; miss = TRUE;
  1317.                      for (asource = Sources; 
  1318.                   asource != NULL ; asource = asource->nextSource) {
  1319.                     k++;
  1320.                             if (asource->thisSource != NULL) 
  1321.                       if (!strncasecmp(user_key,
  1322.                 asource->thisSource->name, strlen(user_key))) {
  1323.                             selection_display(k);
  1324.                                 source_selection = k;
  1325.                 miss = FALSE;
  1326.                     break;
  1327.                               }
  1328.                     }
  1329.                           if (miss) PrintStatus("Unable to find source");
  1330.                         }
  1331.                         break;
  1332.  
  1333.         case '='  : k = 0;
  1334.             for (asource = Sources; 
  1335.               asource != NULL ; asource = asource->nextSource) {
  1336.               k++;
  1337.               if (FindSource(Selected_Sources,
  1338.                 asource->thisSource->name)) {
  1339.         
  1340.                    Selected_Sources = DeleteSource(Selected_Sources,asource->thisSource);
  1341.                    question->numsources--;
  1342.                    question->modified=TRUE;
  1343.             display_source_selected(Selected_Sources,asource->thisSource);
  1344.             source_selected(Selected_Sources,asource->thisSource,k);
  1345.             selection_display(k);
  1346.                 }
  1347.                         }
  1348.                         break;
  1349.  
  1350.             case '.'  : ;
  1351.         case ' '  : k = 0;
  1352.             for (asource = Sources; 
  1353.               asource != NULL ; asource = asource->nextSource) {
  1354.               k++;
  1355.               if (k==selection) break;
  1356.             }
  1357.             if (FindSource(Selected_Sources,asource->thisSource->name)) {
  1358.         
  1359.                Selected_Sources = DeleteSource(Selected_Sources,asource->thisSource);
  1360.                            question->numsources--;
  1361.                question->modified=TRUE;
  1362.                         }
  1363.             else {
  1364.                Selected_Sources = AddSource(Selected_Sources,asource->thisSource);
  1365.                            question->numsources++;
  1366.                question->modified=TRUE;
  1367.                         }
  1368.             display_source_selected(Selected_Sources,asource->thisSource);
  1369.             source_selected(Selected_Sources,asource->thisSource,selection);
  1370.             selection_display(selection);
  1371.             break;
  1372.  
  1373.             case 14   : ;
  1374.         case 'j'  : selection_display(selection+1);
  1375.                         source_selection = selection;
  1376.             break;
  1377.  
  1378.             case 16   : ;
  1379.         case 'k'  : selection_display(selection-1);
  1380.                         source_selection = selection;
  1381.             break;
  1382.         case 'q'  : return(LEAVEPROGRAM);
  1383.         case 'r'  : if(question->numresdocs > 0) return(SHOWRESULTS);break;
  1384.         case 's'  : return(GETSOURCES);
  1385.         case 10   : k = 0;
  1386.             for (asource = Sources; 
  1387.               asource != NULL ; asource = asource->nextSource) {
  1388.               k++;
  1389.               if (k==selection) break;
  1390.             }
  1391.             if (NULL == FindSource(Selected_Sources,asource->thisSource)) {
  1392.         
  1393.                Selected_Sources = AddSource(Selected_Sources,asource->thisSource);
  1394.                            question->numsources++;
  1395.                question->modified=TRUE;
  1396.                         }
  1397.             display_source_selected(Selected_Sources,asource->thisSource);
  1398.             source_selected(Selected_Sources,asource->thisSource,selection);
  1399.             selection_display(selection);
  1400.                         return(nextstate(question)); 
  1401.  
  1402.         case 'w'  : return(GETKEYWORDS);
  1403.  
  1404.         case  18  : ;
  1405.         case '\f' : wrefresh(curscr);
  1406.                         break;
  1407.  
  1408.         case 4    : ;
  1409.             case 22   : ; /* ctrl-v */
  1410.         case 'J'  : selection_display(selection+page_length);
  1411.                         source_selection = selection;
  1412.             break;
  1413.  
  1414.         case 21   : ;
  1415.         case 'K'  : selection_display(selection-page_length);
  1416.                         source_selection = selection;
  1417.             break;
  1418.  
  1419.          default :   if (isdigit(user_key[0])) {
  1420.               digit_str[0] = user_key[0];
  1421.               digit_str[1] = '\0';
  1422.               mvprintw(LINES-3,0,"Source Number: ");
  1423.               get_input_string(digit_str);
  1424.              if (atoi(digit_str)!= 0) {
  1425.                     selection_display(atoi(digit_str));
  1426.                 }
  1427.             standend();
  1428.               mvprintw(LINES-3,0," ");
  1429.               clrtoeol();
  1430.               mvprintw(LINES-3,0,"Keywords:");
  1431.               mvprintw(LINES-3,10,"%s",question->keywords);
  1432.                 }
  1433.      }
  1434.    }
  1435. }
  1436.  
  1437. void
  1438. mail_command(question)
  1439. Question question;
  1440. {
  1441.   char tmpstr[STRINGSIZE];
  1442.   display_prompt("Enter your e-mail address; ^C to cancel");
  1443.   standout();
  1444.   tmpstr[0]='\0';
  1445.   strcat(tmpstr,"mail ");
  1446.   mvprintw(LINES-3,0,"Address:");
  1447.   standend();
  1448.   move(LINES-3,9);
  1449.   if (get_input_string(command)) {
  1450.      standend();
  1451.      mvprintw(LINES-3,0,"Address:");
  1452.      refresh();
  1453.      strcat(tmpstr,command);
  1454.      mvprintw(LINES-2,0,tmpstr);
  1455.      PipeWaisDocument(question, findDoc(question->ResultDocuments,selection-1),tmpstr);
  1456.      cbreak();
  1457.      screenstart();
  1458.   }
  1459.   standend();
  1460.   mvprintw(LINES-3,0,"\n");
  1461.   display_prompt("");
  1462.   refresh();
  1463. }
  1464.  
  1465.  
  1466. void
  1467. pipe_command(question)
  1468. Question question;
  1469. {
  1470.   display_prompt("Enter the command to be executed on this item; ^C to cancel");
  1471.   standout();
  1472.   mvprintw(LINES-3,0,"Command:");
  1473.   standend();
  1474.   move(LINES-3,9);
  1475.   if (get_input_string(command)) {
  1476.      standend();
  1477.      mvprintw(LINES-3,0,"Command:");
  1478.      refresh();
  1479.      PipeWaisDocument(question, findDoc(question->ResultDocuments,selection-1),command);
  1480.      cbreak();
  1481.      noecho();
  1482.      PrintStatus("Press any key to continue"); 
  1483.      getch();
  1484.      cbreak();
  1485.      screenstart();
  1486.   }
  1487.   standend();
  1488.   mvprintw(LINES-3,0,"\n");
  1489.   display_prompt("");
  1490.   refresh();
  1491. }
  1492.  
  1493.  
  1494. keyword_state(question)
  1495. Question question;
  1496. {
  1497.   display_prompt("Enter keywords with spaces between them; <return> to search; ^C to cancel");
  1498.   standout();
  1499.   mvprintw(LINES-3,0,"Keywords:");
  1500.   standend();
  1501.   move(LINES-3,10);
  1502.   strcpy(keywords,question->keywords);
  1503.   if (get_input_string(keywords)) {
  1504.      standend();
  1505.      mvprintw(LINES-3,0,"Keywords:");
  1506.      refresh();
  1507.      strcpy(question->keywords,keywords);
  1508.      question->modified = TRUE;
  1509.      return(MAKEQUERY);
  1510.   }
  1511.   standend();
  1512.   mvprintw(LINES-3,0,"Keywords:");
  1513.   mvprintw(LINES-3,10,"%s",question->keywords);
  1514.   refresh();
  1515.   return(GETSOURCES);
  1516. }
  1517.  
  1518. void
  1519. result_screen(question)
  1520. Question question;
  1521. {
  1522.   DocList doclist;
  1523.   DocumentID current_doc;
  1524.   int k;
  1525.   int doc_count;
  1526.   char fstr[STRINGSIZE];
  1527.   char *sourcename;
  1528.  
  1529.   doc_count = question->numresdocs;
  1530.  
  1531.   title_display("Search Results","Items:", doc_count);
  1532.  
  1533.   if (option_widetitles==FALSE) {
  1534.   mvprintw(1,2,"#    Score     Source                       Title                       Lines");
  1535.   sprintf(fstr,"%%03d:   [%%4d] (%%15.15s)  %%-%d.%ds %%5ld\n",COLS-40,COLS-40);
  1536.   }
  1537.   else {
  1538.   mvprintw(1,2,"#    Score                               Title                          Lines");
  1539.   sprintf(fstr,"%%03d:   [%%4d]  %%-%d.%ds %%5ld\n",COLS-22,COLS-22);
  1540.   }
  1541.  
  1542.   if (question->ResultDocuments != NULL) {
  1543.   k = 1;
  1544.   for ( doclist = question->ResultDocuments; doclist != NULL ;
  1545.       doclist = doclist->nextDoc) {
  1546.  
  1547.      current_doc = doclist->thisDoc;
  1548.      if (current_doc != NULL) {
  1549.        sourcename = firstphrase(trim_junk(current_doc->doc->source));
  1550.        if (NULL != strrchr(sourcename,'/')) {
  1551.           sourcename = strrchr(sourcename,'/');
  1552.           sourcename++;
  1553.        }
  1554.     if (option_widetitles==TRUE) 
  1555.        sprintf(select_line[k],fstr, k, current_doc->rawScore, 
  1556.            firstphrase(trim_junk(current_doc->doc->headline)),
  1557.                current_doc->doc->numLines);
  1558.        else 
  1559.        sprintf(select_line[k],fstr, k, current_doc->rawScore, sourcename,
  1560.            firstphrase(trim_junk(current_doc->doc->headline)),
  1561.                current_doc->doc->numLines);
  1562.       k++;
  1563.      }
  1564.    }
  1565.  }
  1566.   selection = result_selection;
  1567.   current_page = -1;
  1568.   max_selection=doc_count;
  1569.   page_length= MIN(LINES-6, doc_count);
  1570.   selection_display(NOSELECTION);
  1571. }
  1572.  
  1573. programstate
  1574. result_state(question)
  1575. Question question;
  1576. {
  1577.  
  1578.   DocList doclist;
  1579.   DocumentID current_doc;
  1580.   char user_key[STRINGSIZE];
  1581.   char digit_str[STRINGSIZE];
  1582.   int k,miss;
  1583.  
  1584.   selection_display(selection);
  1585.  
  1586.   digit_str[0]='\0';
  1587.   while(TRUE) {
  1588.     display_prompt("<space> selects, arrows move, w for keywords, s for sources, ? for help");
  1589.     user_key[0]=getch();
  1590.     switch(user_key[0]) {
  1591.     
  1592.     case 'H' : show_swais_history();
  1593.       state=UNKNOWN;
  1594.       return(SHOWRESULTS);
  1595.  
  1596.     case 'h' : ;
  1597.     case '?' : show_search_results_help();
  1598.       state=UNKNOWN;
  1599.       return(SHOWRESULTS);
  1600.          
  1601.       /* forgive me: hardwired arrow keys for vt100 since we're
  1602.      not using SysV curses and bsd curses lacks key support  */
  1603.     case '\033' : user_key[1]=getch();
  1604.       user_key[2]=getch();
  1605.       user_key[3]='\0';
  1606.       if (strcmp(user_key, "\033[A")) {
  1607.     selection_display(selection+1);
  1608.     result_selection = selection;
  1609.     break;
  1610.       }
  1611.       if (strcmp(user_key, "\033[B")) {
  1612.     selection_display(selection-1);
  1613.     result_selection = selection;
  1614.     break;
  1615.       }
  1616.  
  1617.     /* emacs <meta>v page previous */
  1618.     if (user_key[1]=='v') {
  1619.       selection_display(selection-page_length);
  1620.       result_selection = selection;
  1621.       break;
  1622.     }
  1623.  
  1624.     case 'o' : return(GETOPTIONS);
  1625.  
  1626.     case ','  : ;
  1627.     case 'v'  : view_result_info(findDoc(question->ResultDocuments,selection-1));
  1628.       state=UNKNOWN;
  1629.       return(SHOWRESULTS);
  1630.  
  1631.     case 'u'  : UseWaisDocument(question, findDoc(question->ResultDocuments,selection-1));
  1632.       break;
  1633.  
  1634.         case 10   : ;
  1635.         case ' '  : PipeWaisDocument(question, 
  1636.                 findDoc(question->ResultDocuments,selection-1), 
  1637.                 "${PAGER-more}");
  1638.                       if (option_pagerpause==TRUE) {
  1639.                   cbreak();
  1640.                   noecho();
  1641.                   PrintStatus("Press any key to continue"); 
  1642.                   getch();
  1643.                       }
  1644.               screenstart();
  1645.               state=UNKNOWN;
  1646.               return(SHOWRESULTS);
  1647.  
  1648.         case '|'  : ;
  1649.         case 'c'  : pipe_command(question);
  1650.               state=UNKNOWN;
  1651.               return(SHOWRESULTS);
  1652.  
  1653.         case 14   : ;
  1654.         case 'j'  : selection_display(selection+1); 
  1655.               result_selection = selection;
  1656.               break;
  1657.  
  1658.         case 16   : ;
  1659.         case 'k'  : selection_display(selection-1); 
  1660.               result_selection = selection;
  1661.               break;
  1662.  
  1663.         case 'q'  : return(LEAVEPROGRAM);
  1664.         case 's'  : return(GETSOURCES);
  1665.         case 'w'  : return(GETKEYWORDS);
  1666.                 
  1667.         case  18  : ;
  1668.         case '\f' : wrefresh(curscr);
  1669.                         break;
  1670.  
  1671.  
  1672.             case '/'  : user_key[0] = '\0';
  1673.               mvprintw(LINES-3,0,"Item Name: ");
  1674.               get_input_string(user_key);
  1675.             standend();
  1676.               mvprintw(LINES-3,0," ");
  1677.               clrtoeol();
  1678.             refresh();
  1679.              if (strlen(user_key)) {
  1680.                k=0; miss = TRUE;
  1681.                   for ( doclist = question->ResultDocuments; 
  1682.                  doclist != NULL ; doclist = doclist->nextDoc) {
  1683.                current_doc = doclist->thisDoc;
  1684.                    k++;
  1685.                if (current_doc != NULL)
  1686.                if (!strncasecmp(user_key,current_doc->doc->headline,
  1687.                 strlen(user_key))) {
  1688.                             selection_display(k);
  1689.                                 result_selection = k;
  1690.                 miss = FALSE;
  1691.                     break;
  1692.                               }
  1693.                     }
  1694.                           if (miss) PrintStatus("Unable to find item");
  1695.                         }
  1696.                         break;
  1697.  
  1698.      case 'm'  : mail_command(question);
  1699.                      state=UNKNOWN;
  1700.                  return(SHOWRESULTS);
  1701.  
  1702.      case 4    : ;
  1703.          case 22   : ; /* emacs ctrl-v */
  1704.      case 'J'  : selection_display(selection+page_length);
  1705.                      result_selection = selection;
  1706.              break;
  1707.  
  1708.      case 21   : ;
  1709.          case 'K'  : selection_display(selection-page_length); 
  1710.                      result_selection = selection;
  1711.                      break;
  1712.  
  1713.          default :   if (isdigit(user_key[0])) {
  1714.               digit_str[0] = user_key[0];
  1715.               digit_str[1] = '\0';
  1716.               mvprintw(LINES-3,0,"Item Number: ");
  1717.               get_input_string(digit_str);
  1718.              if (atoi(digit_str)!= 0) {
  1719.                     selection_display(atoi(digit_str));
  1720.                result_selection = selection;
  1721.                 }
  1722.             standend();
  1723.               mvprintw(LINES-3,0," ");
  1724.                         clrtoeol();
  1725.       }
  1726.     }
  1727.   } 
  1728. }
  1729.  
  1730. void
  1731. main(argc, argv)
  1732. int argc;
  1733. char **argv;
  1734. {
  1735.   Question question;
  1736.   SList asource;
  1737.   char msg[STRINGSIZE];
  1738.   char *getenv();
  1739.   char sourcename[STRINGSIZE];
  1740.   int i;
  1741.  
  1742.   if (command_name = (char*)rindex(argv[0], '/'))
  1743.     command_name++;
  1744.   else
  1745.     command_name = argv[0];
  1746.  
  1747.   command[0]='\0';
  1748.  
  1749.   sdir = cdir = NULL;
  1750.   keywords[0] = 0;
  1751.   sourcename[0] = 0;
  1752.  
  1753.   maxDocs = 40;
  1754.  
  1755.   i = 1;
  1756.   for(; i < argc; i++) {
  1757.     if (*argv[i] == '-') {
  1758.       argv[i]++;
  1759.       switch (*argv[i]) {
  1760.       case 'C':
  1761.     i++;
  1762.     if(i >= argc) {
  1763.       fprintf(stderr, "Too few arguments: common source directory missing.\n");
  1764.       exit(1);
  1765.       }
  1766.     cdir = argv[i];
  1767.     break;
  1768.       case 'S':
  1769.     i++;
  1770.     if(i >= argc) {
  1771.       fprintf(stderr, "Too few arguments: user source directory missing.\n");
  1772.       exit(1);
  1773.       }
  1774.     sdir = argv[i];
  1775.     break;
  1776.       case 's':
  1777.     i++;
  1778.     if(i >= argc) {
  1779.       fprintf(stderr, "Too few arguments: source name missing.\n");
  1780.       exit(1);
  1781.       }
  1782.         sprintf(sourcename,"%s.src", argv[i]);
  1783.     break;
  1784.       case 'h':
  1785.     usage(argv[0]);
  1786.     exit(0);
  1787.     break;
  1788.       default:
  1789.     fprintf(stderr, "Unknown option: %s.\n", argv[i]);
  1790.     exit(1);
  1791.       }
  1792.     }
  1793.     else {
  1794.       if((strlen(keywords) + strlen(argv[i]) + 1) < STRINGSIZE) {
  1795.         if (strlen(keywords)) strcat(keywords, " ");
  1796.     strcat(keywords, argv[i]);
  1797.       }
  1798.     }
  1799.   }
  1800.       
  1801.    if(sdir == NULL) {
  1802.       if((sdir = getenv("WAISSOURCEDIR")) == NULL) {
  1803.      sprintf(msg, "%s/wais-sources", getenv("HOME"));
  1804.      sdir = s_strdup(msg);
  1805.       }
  1806.    }
  1807.    sdir = fixdirname(sdir);
  1808.    ReadSourceDirectory(sdir, TRUE);
  1809.  
  1810.    if(cdir == NULL) {
  1811.       if((cdir = getenv("WAISCOMMONSOURCEDIR")) == NULL) {
  1812.      strcpy(msg, COMMON_SOURCE_DIR);
  1813.      cdir = s_strdup(msg);
  1814.       }
  1815.    }
  1816.    cdir = fixdirname(cdir);
  1817.    ReadSourceDirectory(cdir, TRUE);
  1818.  
  1819.   Refresh_sources();
  1820.  
  1821.   strcpy(options[1].name, "widetitles");
  1822.   strcpy(options[1].desc, "Show wide Item titles on Results Screen by omitting source name"); 
  1823.   options[1].type = OPTION_BOOLEAN;
  1824.   options[1].var.intptr  = &option_widetitles;
  1825.   options[1].update = null;
  1826.  
  1827.   strcpy(options[2].name, "sortsources");
  1828.   strcpy(options[2].desc, "Display sources sorted alphabetically rather than directory order");
  1829.   options[2].type = OPTION_BOOLEAN;
  1830.   options[2].var.intptr = &option_sortsources;
  1831.   options[2].update = Refresh_sources;
  1832.  
  1833.   strcpy(options[3].name, "sourcedir");
  1834.   strcpy(options[3].desc, "Personal WAIS source directory containing *.src description files");
  1835.   options[3].type = OPTION_STRING;
  1836.   options[3].var.charptr = sdir;
  1837.   options[3].update = Refresh_sources;
  1838.  
  1839.   strcpy(options[4].name, "commondir");
  1840.   strcpy(options[4].desc, "Common WAIS source directory containing *.src description files");
  1841.   options[4].type = OPTION_STRING;
  1842.   options[4].var.charptr = cdir;
  1843.   options[4].update = Refresh_sources;
  1844.  
  1845.   strcpy(options[5].name, "pagerpause");
  1846.   strcpy(options[5].desc, "Pause after displaying a document via the external pager");
  1847.   options[5].type = OPTION_BOOLEAN;
  1848.   options[5].var.intptr  = &option_pagerpause;
  1849.   options[5].update = null;
  1850.  
  1851.   strcpy(options[6].name, "maxitems");
  1852.   strcpy(options[6].desc, "Maximum items (documents) returned in a single query");
  1853.   options[6].type = OPTION_INTEGER;
  1854.   options[6].var.intptr  = &maxDocs;
  1855.   options[6].update = null;
  1856.  
  1857.    question = (Question)s_malloc(sizeof(_Question));
  1858.    question->numsources=0;
  1859.    question->modified=FALSE;
  1860.  
  1861.    screenstart();
  1862.  
  1863.    state = UNKNOWN;
  1864.  
  1865.    if (sourcename[0] != 0)
  1866.      for(asource = Sources; asource != NULL; asource = asource->nextSource)  
  1867.        if (!strcmp(sourcename, asource->thisSource->name)) {
  1868.      Selected_Sources = AddSource(Selected_Sources, asource->thisSource);
  1869.      question->numsources++;
  1870.          question->modified=TRUE;
  1871.        }
  1872.  
  1873.    if (keywords[0]!='\0') {
  1874.      strcpy(question->keywords,keywords);
  1875.      question->modified = TRUE;
  1876.    }
  1877.  
  1878.    new_state = nextstate(question);
  1879.  
  1880.    if (setjmp(main_env)!=0) {
  1881.       state=UNKNOWN;
  1882.       new_state=GETSOURCES;
  1883.    }
  1884.  
  1885.    while (TRUE) {
  1886.    
  1887.       if (new_state!=state) {
  1888.         if ((new_state / 10) != (state / 10)) {
  1889.           clear();
  1890.           switch (new_state) {
  1891.          case GETSOURCES: ;
  1892.          case GETKEYWORDS: ;
  1893.          case MAKEQUERY: source_screen(question); break;
  1894.          case SHOWRESULTS: result_screen(question); break;
  1895.          case GETOPTIONS : option_screen(question); break;
  1896.          case LEAVEPROGRAM: break; 
  1897.           }
  1898.         }
  1899.         else {
  1900.        selection_display(NOSELECTION);
  1901.        display_prompt("");
  1902.         }
  1903.         state = new_state;
  1904.       }
  1905.  
  1906.       switch (state) {
  1907.  
  1908.     case MAKEQUERY: 
  1909.        new_state = makequery_state(question);
  1910.        break;
  1911.  
  1912.     case GETKEYWORDS: ;
  1913.        new_state = keyword_state(question);
  1914.        break;
  1915.  
  1916.     case GETSOURCES: 
  1917.        new_state = source_state(question);
  1918.        break;
  1919.  
  1920.     case SHOWRESULTS:
  1921.        new_state = result_state(question);
  1922.        break;
  1923.  
  1924.     case GETOPTIONS:
  1925.        new_state = option_state(question);
  1926.        break;
  1927.  
  1928.     case LEAVEPROGRAM:
  1929.        screenend();
  1930.        exit(0);
  1931.       }
  1932.     }
  1933. }
  1934.